package com.fowo.api.common.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private static ConcurrentHashMap<Object, SoftReference<DelayedGetContextCallback>> delayedGetMap;

    static {
        delayedGetMap = new ConcurrentHashMap<>();
    }

    public static ApplicationContext getApplicationContext() {
        return ContextHolder.applicationContext;
    }

    private static void runCallbacks() {
        HashMap<Object, SoftReference<DelayedGetContextCallback>> map = new HashMap(delayedGetMap);
        for(Map.Entry<Object, SoftReference<DelayedGetContextCallback>> entry : map.entrySet()) {
            if (entry.getValue().get() != null) {
                Objects.requireNonNull(entry.getValue().get()).run(applicationContext);
            }
            delayedGetMap.remove(entry.getKey());
        }
    }

    public static void delayedGetContext(Object refObject, DelayedGetContextCallback callback) throws Exception {
        if (applicationContext != null) {
            callback.run(applicationContext);
            return;
        }
        delayedGetMap.put(refObject, new SoftReference<>(callback));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ContextHolder.applicationContext = applicationContext;
        ContextHolder.runCallbacks();
    }

    public interface DelayedGetContextCallback {
        void run(ApplicationContext applicationContext);
    }
}
